package com.etone.fileServer.service;

import com.etone.fileServer.dto.file.FileMakeDTO;
import com.etone.fileServer.dto.file.FileMoveOrCopyDTO;
import com.etone.fileServer.dto.file.FileRenameDTO;
import com.etone.fileServer.error.CustomParameterizedException;
import com.etone.fileServer.utils.SignUtil;
import com.etone.fileServer.vo.file.FileVO;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: sovy
 * @date: 2020/11/4
 * @description:
 */
@Service
public class FileManagerService {
    /**
     * 获取文件列表
     *
     * @param path      目录
     * @param timestamp
     * @param sign
     * @return
     */
    public List<FileVO> list(String path, Long timestamp, String sign) {
        SignUtil.checkSignThrow(path, timestamp, sign);
        File directoryFile = new File(path);
        checkDirectory(directoryFile);
        File[] fileList = directoryFile.listFiles();
        if (fileList == null || fileList.length == 0) {
            return new ArrayList<>();
        }
        return Arrays.asList(fileList).stream().map(file ->
                FileVO
                        .builder()
                        .name(file.getName())
                        .absolutePath(file.getAbsolutePath())
                        .extension(file.isFile() ? FilenameUtils.getExtension(file.getName()) : null)
                        .size(FileUtils.sizeOf(file))
                        .isFile(file.isFile())
                        .parent(file.getParent())
                        .lastModifyTime(Instant.ofEpochMilli(file.lastModified()).atZone(ZoneId.systemDefault()).toLocalDateTime())
                        .build()
        ).collect(Collectors.toList());
    }

    /**
     * 文件重命名
     *
     * @param fileRenameDTO
     * @param timestamp
     * @param sign
     */
    public void rename(FileRenameDTO fileRenameDTO, Long timestamp, String sign) {
        SignUtil.checkSignThrow(fileRenameDTO, timestamp, sign);
        File file = new File(fileRenameDTO.getFilePath());
        if (!file.exists()) {
            throw new CustomParameterizedException("文件不存在");
        }
        if (file.getName().equals(fileRenameDTO.getNewName())) {
            return;
        }
        File newFile = new File(file.getParent() + "/" + fileRenameDTO.getNewName());
        if (newFile.exists()) {
            throw new CustomParameterizedException("文件已存在");
        }
        boolean renameTo = file.renameTo(newFile);
        if (!renameTo) {
            throw new CustomParameterizedException("重命名失败");
        }
    }

    /**
     * 文件移动
     *
     * @param fileMoveOrCopyDTOS
     * @param timestamp
     * @param sign
     */
    public void move(List<FileMoveOrCopyDTO> fileMoveOrCopyDTOS, Long timestamp, String sign) {
        SignUtil.checkSignThrow(fileMoveOrCopyDTOS, timestamp, sign);
        fileMoveOrCopyDTOS.forEach(fileMoveOrCopyDTO -> {
            if (fileMoveOrCopyDTO.getSourceFile().equals(fileMoveOrCopyDTO.getDestFile())) {
                return;
            }
            File file = new File(fileMoveOrCopyDTO.getSourceFile());
            if (!file.exists()) {
                throw new CustomParameterizedException("文件不存在");
            }

            //校验目标文件
            File targetFile = new File(fileMoveOrCopyDTO.getDestFile());
            if ((fileMoveOrCopyDTO.getIsReplace() == null || !fileMoveOrCopyDTO.getIsReplace()) && targetFile.exists()) {
                throw new CustomParameterizedException("文件已存在");
            }
            checkDirectory(targetFile.getParentFile());

            try {
                if (fileMoveOrCopyDTO.getIsReplace() != null && fileMoveOrCopyDTO.getIsReplace()) {
                    //文件覆盖
                    Files.move(Paths.get(fileMoveOrCopyDTO.getSourceFile()), Paths.get(fileMoveOrCopyDTO.getDestFile()), StandardCopyOption.REPLACE_EXISTING);
                } else {
                    Files.move(Paths.get(fileMoveOrCopyDTO.getSourceFile()), Paths.get(fileMoveOrCopyDTO.getDestFile()));
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new CustomParameterizedException(e.getMessage());
            }
        });
    }

    /**
     * 复制文件
     *
     * @param fileMoveOrCopyDTOS
     * @param timestamp
     * @param sign
     */
    public void copy(List<FileMoveOrCopyDTO> fileMoveOrCopyDTOS, Long timestamp, String sign) {
        SignUtil.checkSignThrow(fileMoveOrCopyDTOS, timestamp, sign);
        fileMoveOrCopyDTOS.forEach(fileMoveOrCopyDTO -> {
            if (fileMoveOrCopyDTO.getSourceFile().equals(fileMoveOrCopyDTO.getDestFile())) {
                return;
            }
            File file = new File(fileMoveOrCopyDTO.getSourceFile());
            if (!file.exists()) {
                throw new CustomParameterizedException("文件不存在");
            }

            //校验目标文件
            File targetFile = new File(fileMoveOrCopyDTO.getDestFile());
            if ((fileMoveOrCopyDTO.getIsReplace() == null || !fileMoveOrCopyDTO.getIsReplace()) && targetFile.exists()) {
                throw new CustomParameterizedException("文件已存在");
            }
            checkDirectory(targetFile.getParentFile());
            try {
                if (fileMoveOrCopyDTO.getIsReplace() != null && fileMoveOrCopyDTO.getIsReplace()) {
                    //文件覆盖
                    Files.copy(Paths.get(fileMoveOrCopyDTO.getSourceFile()), Paths.get(fileMoveOrCopyDTO.getDestFile()), StandardCopyOption.REPLACE_EXISTING);
                    if (file.isFile()) {
                        FileUtils.copyFile(file, targetFile, true, StandardCopyOption.REPLACE_EXISTING);
                    } else {
                        FileUtils.copyDirectory(file, targetFile, null, true, StandardCopyOption.REPLACE_EXISTING);
                    }

                } else {
                    if (file.isFile()) {
                        FileUtils.copyFile(file, targetFile, true);
                    } else {
                        FileUtils.copyDirectory(file, targetFile, true);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new CustomParameterizedException(e.getMessage());
            }
        });
    }

    /**
     * 删除文件
     *
     * @param fileStrs
     * @param timestamp
     * @param sign
     */
    public void delete(List<String> fileStrs, Long timestamp, String sign) {
        SignUtil.checkSignThrow(fileStrs, timestamp, sign);
        fileStrs.forEach(fileStr -> {
            File file = new File(fileStr);
            if (!file.exists()) {
                throw new CustomParameterizedException("文件不存在");
            }
            try {
                if (file.isDirectory()) {
                    FileUtils.deleteDirectory(file);
                } else {
                    Files.delete(Paths.get(fileStr));
                }

            } catch (IOException e) {
                e.printStackTrace();
                throw new CustomParameterizedException(e.getMessage());
            }
        });

    }

    /**
     * 创建目录
     *
     * @param fileMakeDTO
     * @param timestamp
     * @param sign
     */
    public void mkdir(FileMakeDTO fileMakeDTO, Long timestamp, String sign) {
        SignUtil.checkSignThrow(fileMakeDTO, timestamp, sign);
        if (CollectionUtils.isEmpty(fileMakeDTO.getNames())) {
            throw new CustomParameterizedException("目录不能为空");
        }
        File directory = new File(fileMakeDTO.getPath());
        checkDirectory(directory);

        for (String name : fileMakeDTO.getNames()) {
            File newFile = new File(directory.getAbsolutePath() + "/" + name);
            if (!newFile.exists()) {
                newFile.mkdir();
            }
        }

    }

    /**
     * 校验文件
     */
    private void checkFile(File file) {
        if (!file.exists()) {
            throw new CustomParameterizedException("文件不存在");
        }
        if (!file.isFile()) {
            throw new CustomParameterizedException("无效文件");
        }
    }

    /**
     * 校验目录
     */
    private void checkDirectory(File file) {
        if (!file.exists()) {
            throw new CustomParameterizedException("目录不存在");
        }
        if (!file.isDirectory()) {
            throw new CustomParameterizedException("无效目录");
        }
    }

}
